package com.gonsin.gview.common.services.impl;

import com.gonsin.gview.common.po.FileUploadBo;
import com.gonsin.gview.common.services.IUpdateService;
import com.gonsin.gview.common.utils.MD5Util;
import com.gonsin.gview.common.utils.PathUtils;
import com.gonsin.gview.logic.config.GViewFileProperties;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

@Service
@Primary
public class UpdateServiceImpl implements IUpdateService {

    private static final Map<String, Holder> holderMap = new ConcurrentHashMap<>();

    @Autowired
    private GViewFileProperties config;

    /**
     * 分片上传
     * 先调用readyToUpdate()方法获取Key
     */
    @Override
    public void update(String key, MultipartFile piece, int index, boolean end) {
        Holder holder = holderMap.get(key);
        FileHolder fileHolder = new FileHolder();
        fileHolder.index = index;
        fileHolder.piece = new File(config.getTempPath()
                + File.separator + "pieces"
                + File.separator + key
                + File.separator + index + ".piece");
        File parent = fileHolder.piece.getParentFile();
        if (!parent.exists()) {
            parent.mkdirs();
        }
        if (fileHolder.piece.exists()) {
            try {
                FileUtils.forceDelete(fileHolder.piece);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        try {
            fileHolder.piece.createNewFile();
            piece.transferTo(fileHolder.piece);
        } catch (IOException e) {
            e.printStackTrace();
        }

        holder.fileHolders.add(fileHolder);

        if (end) {
            // 集合所有的文件分片
            List<FileHolder> pieces = new ArrayList<>();
            pieces.addAll(holder.fileHolders);
            pieces.sort(Comparator.comparingInt(item -> item.index));
            File realFile = holder.realFile;
            if (realFile != null && realFile.exists()) {
                realFile.delete();
            }
            try {
                realFile.createNewFile();
            } catch (IOException e) {
                e.printStackTrace();
            }

            for (int i = 0; i < pieces.size(); i++) {
                FileHolder file = pieces.get(i);
                try {
                    byte[] data = FileUtils.readFileToByteArray(file.piece);
                    FileUtils.writeByteArrayToFile(realFile, data, true);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

    }

    @Override
    public String readyToUpdate(String url, String suffix) {
        String key = RandomStringUtils.random(32, true, true);
        Holder holder = new Holder();

        File realFile;
        if (StringUtils.isEmpty(url)) {
            realFile = new File(config.getTempPath()
                    + File.separator + "pieces"
                    + File.separator + "total_" + key + "." + suffix);
        } else {
            realFile = new File(PathUtils.getPathFromUrl(config.getTempPath(), url + "." + suffix));
        }
        holder.setRealFile(realFile);
        holderMap.put(key, holder);
        return key;
    }

    @Override
    public File getFileByKey(String key) {
        Holder holder = holderMap.get(key);
        if (holder == null) {
            return null;
        }
        return holder.realFile;
    }

    @Override
    public void removeFile(long key) {
        Holder holder = holderMap.remove(key);
        try {
            FileUtils.forceDelete(holder.realFile);
        } catch (IOException e) {
            e.printStackTrace();
        }
        List<FileHolder> fileHolders = holder.fileHolders;
        File folder = null;
        for (int i = 0; i < fileHolders.size(); i++) {
            FileHolder fileHolder = fileHolders.get(i);
            try {
                folder = fileHolder.piece.getParentFile();
                FileUtils.forceDelete(fileHolder.piece);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        if (folder != null) {
            try {
                FileUtils.forceDelete(folder);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    @Override
    public FileUploadBo getUrlByKey(String key) {
        Holder holder = holderMap.get(key);
        if (holder == null) {
            return null;
        }
        String url = null;
        String md5 = null;
        if (holder.realFile != null) {
            url = PathUtils.getUrlFromPath(config.getTempPath(), holder.realFile.getAbsolutePath());
            if (holder.realFile.exists()) {
                md5 = MD5Util.getMd5ByFile(holder.realFile);
            }
        }
        return new FileUploadBo(url, md5);
    }

    class Holder {
        private List<FileHolder> fileHolders = new ArrayList<>();
        private File realFile;

        public List<FileHolder> getFileHolders() {
            return fileHolders;
        }

        public Holder setFileHolders(List<FileHolder> fileHolders) {
            this.fileHolders = fileHolders;
            return this;
        }

        public File getRealFile() {
            return realFile;
        }

        public Holder setRealFile(File realFile) {
            this.realFile = realFile;
            return this;
        }
    }

    class FileHolder {
        private File piece;
        private int index;
    }
}
